<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta http-equiv="Content-Style-Type" content="text/css">
<title></title>
<meta name="Generator" content="Cocoa HTML Writer">
<meta name="CocoaVersion" content="824.48">
<style type="text/css">
p.p1 {margin: 0.0px 0.0px 0.0px 0.0px; font: 13.0px Helvetica; color: #000000}
p.p2 {margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Helvetica; color: #000000; min-height: 14.0px}
p.p3 {margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Helvetica; color: #000000}
p.p4 {margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Helvetica; color: #000000}
p.p5 {margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Helvetica}
p.p6 {margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Helvetica; color: #bf0000}
p.p7 {margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Helvetica; color: #0000bf}
p.p8 {margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Helvetica; color: #606060}
p.p9 {margin: 0.0px 0.0px 0.0px 0.0px; font: 9.0px Monaco}
p.p10 {margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Helvetica; color: #bf0000; min-height: 14.0px}
p.p11 {margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Helvetica; min-height: 14.0px}
span.s1 {font: 18.0px Helvetica}
span.s2 {color: #0000bf}
span.s3 {color: #000000}
span.s4 {color: #007300}
span.s5 {font: 12.0px Lucida Grande}
span.s6 {color: #001cab}
span.s7 {font: 12.0px Helvetica}
span.Apple-tab-span {white-space:pre}
</style>
</head>
<body>
<p class="p1"><span class="s1"><b>PV_ExtractRepeat<span class="Apple-tab-span">	</span><span class="Apple-tab-span">	</span></b></span><b>extract a repeating loop out from audio</b></p>
<p class="p2"><br></p>
<p class="p3"><span class="s2">PV_ExtractRepeat</span>(chain, loopbuf, loopdur, memorytime, which=0, ffthop=0.5, thresh=1)</p>
<p class="p2"><br></p>
<p class="p4">If you have a signal that consists of some fixed looping audio (e.g. a beat) plus some varying content (e.g. singing), this UGen uses a simple binary-masking technique to try and separate the looping bit from the non-looping bit. The quality of the separation is quite rough, but useful in some circumstances.</p>
<p class="p2"><br></p>
<p class="p5">Note that this unit estimates the loop characteristics online in real time, meaning it takes a few times through the loop before the separation really kicks in. This means that at any point, any novel element is included in the nonrepeating part, even if it's really a loop that's starting.</p>
<p class="p2"><br></p>
<p class="p4">You <b><i>must</i></b> know the <b><i>loop duration</i></b> - this unit will not estimate it for you.<span class="Apple-converted-space"> </span></p>
<p class="p2"><br></p>
<p class="p4"><b>chain</b> - an fft chain</p>
<p class="p5"><span class="s3"><b>loopbuf</b> - a buffer where data about the loop is calculated/stored. </span>num frames should be enough to hold the loop (you'll get a warning if not), num channels should be (fftsize/2 + 1).</p>
<p class="p5"><b>loopdur</b> - duration in seconds of the bit you want extracted. (You can change the loop duration on-the-fly but you'll get some unhelpful results while the unit settles in to the new loop duration.)</p>
<p class="p5"><b>memorytime</b> - how quickly (in seconds) the recursive estimation converges</p>
<p class="p5"><b>which</b> - set to 0 to extract the loop, set to 1 to extract everything else</p>
<p class="p5"><b>ffthop</b> - this should match the hop size used in the FFT. typically 0.5.</p>
<p class="p5"><b>thresh</b> - threshold for allocating bins to repeating/nonrepeating. Default is 1, and raising it means more gets allocated to the repeating part.</p>
<p class="p2"><br></p>
<p class="p2"><br></p>
<p class="p4"><b>Example</b></p>
<p class="p4">In this example we create definite looping and non-looping stuff using some synthetic material, but you might find it more interesting to use DiskIn to read in some dance music...</p>
<p class="p2"><br></p>
<p class="p4">s.boot</p>
<p class="p6">// Create audio containing repeating and varying components, merged in the same channel:</p>
<p class="p4">(</p>
<p class="p4">x = {</p>
<p class="p4"><span class="Apple-tab-span">	</span><span class="s2">var</span> trigs, looplen = 2, loopy, varying;</p>
<p class="p4"><span class="Apple-tab-span">	</span>trigs = <span class="s2">Impulse</span>.kr(6/looplen) + <span class="s2">Impulse</span>.kr(4/looplen);</p>
<p class="p4"><span class="Apple-tab-span">	</span>loopy = <span class="s2">BPF</span>.ar(<span class="s2">WhiteNoise</span>.ar * <span class="s2">EnvGen</span>.ar(<span class="s2">Env</span>.perc(0.01, 0.3), trigs), <span class="s2">LFCub</span>.kr(1/looplen).exprange(100, 5000));</p>
<p class="p4"><span class="Apple-tab-span">	</span>varying = <span class="s2">Pulse</span>.ar(<span class="s2">LFNoise0</span>.kr(6/looplen).exprange(100, 500).cpsmidi.round.midicps) * 0.1;</p>
<p class="p4"><span class="Apple-tab-span">	</span>(loopy + varying).dup</p>
<p class="p4">}.play;</p>
<p class="p4">)</p>
<p class="p6">// Now the thing that will attempt to separate them out again (inc a buffer for it to use):</p>
<p class="p4">~loopbuf = <span class="s2">Buffer</span>.alloc(s, 200, 513);<span class="Apple-converted-space"> </span></p>
<p class="p4">(</p>
<p class="p7"><span class="s3">y = { </span>|which=1, active=1|</p>
<p class="p4"><span class="Apple-tab-span">	</span><span class="s2">var</span> son = <span class="s2">In</span>.ar(0);</p>
<p class="p4"><span class="Apple-tab-span">	</span><span class="s2">var</span> chain = <span class="s2">FFT</span>(<span class="s2">LocalBuf</span>(1024), son);</p>
<p class="p4"><span class="Apple-tab-span">	</span>chain = <span class="s2">PV_ExtractRepeat</span>(chain, ~loopbuf, 2, memorytime:30, which:which);</p>
<p class="p4"><span class="Apple-tab-span">	</span><span class="s2">ReplaceOut</span>.ar(0, <span class="s2">Select</span>.ar(active, [son, <span class="s2">IFFT</span>(chain)]).dup);</p>
<p class="p4">}.play(x, addAction: <span class="s4">\addAfter</span>);</p>
<p class="p4">)</p>
<p class="p6"><span class="s3">y.set(</span><span class="s4">\which</span><span class="s3">, 0) </span>// focus on the nonrepeating bit</p>
<p class="p6"><span class="s3">y.set(</span><span class="s4">\which</span><span class="s3">, 1) </span>// focus on the repeating bit</p>
<p class="p6"><span class="s3">y.set(</span><span class="s4">\active</span><span class="s3">, 0) </span>// back to normal</p>
<p class="p6"><span class="s3">y.set(</span><span class="s4">\active</span><span class="s3">, 1) </span>// filter it again</p>
<p class="p2"><br></p>
<p class="p4">y.free;</p>
<p class="p4">x.free;</p>
<p class="p2"><br></p>
<p class="p2"><br></p>
<p class="p6">//////////////////////////////////////</p>
<p class="p6">// With music:</p>
<p class="p2"><br></p>
<p class="p8"><span class="s3">~track = </span>"~/tmpwavs/Postal Service - Such Great Heights.mp3.2.wav"<span class="s3">.standardizePath; ~bpm=116.6;</span></p>
<p class="p8"><span class="s3">~track = </span>"~/tmpwavs/<span class="s5">Amy Winehouse - Rehab.mp3.wav</span>"<span class="s3">.standardizePath; ~bpm=145.1;</span></p>
<p class="p4">~looplen = 480/~bpm;</p>
<p class="p2"><br></p>
<p class="p9">b = <span class="s6">Buffer</span>.cueSoundFile(s, <span class="s7">~track</span>, 0, 2);</p>
<p class="p4">x = { <span class="s2">DiskIn</span>.ar(2, b) }.play;</p>
<p class="p10"><br></p>
<p class="p6">// Now the thing that will attempt to separate them out again (inc a buffer for it to use):</p>
<p class="p5">~loopbuf = <span class="s2">Buffer</span>.alloc(s, 1000, 513);<span class="Apple-converted-space"> </span></p>
<p class="p5">(</p>
<p class="p7"><span class="s3">y = { </span>|which=1, active=1, thresh=1|</p>
<p class="p5"><span class="Apple-tab-span">	</span><span class="s2">var</span> son = <span class="s2">In</span>.ar(0);</p>
<p class="p5"><span class="Apple-tab-span">	</span><span class="s2">var</span> chain = <span class="s2">FFT</span>(<span class="s2">LocalBuf</span>(1024), son);</p>
<p class="p5"><span class="Apple-tab-span">	</span>chain = <span class="s2">PV_ExtractRepeat</span>(chain, ~loopbuf, ~looplen, memorytime:30, which:which, thresh:thresh);</p>
<p class="p5"><span class="Apple-tab-span">	</span><span class="s2">ReplaceOut</span>.ar(0, <span class="s2">Select</span>.ar(active, [son, <span class="s2">IFFT</span>(chain)]).dup);</p>
<p class="p5">}.play(x, addAction: <span class="s4">\addAfter</span>);</p>
<p class="p5">)</p>
<p class="p6"><span class="s3">y.set(</span><span class="s4">\which</span><span class="s3">, 0) </span>// focus on the nonrepeating bit</p>
<p class="p6"><span class="s3">y.set(</span><span class="s4">\which</span><span class="s3">, 1) </span>// focus on the repeating bit</p>
<p class="p6"><span class="s3">y.set(</span><span class="s4">\active</span><span class="s3">, 0) </span>// back to normal</p>
<p class="p6"><span class="s3">y.set(</span><span class="s4">\active</span><span class="s3">, 1) </span>// filter it again</p>
<p class="p6"><span class="s3">y.set(</span><span class="s4">\which</span><span class="s3">, 0, </span><span class="s4">\thresh</span><span class="s3">, 1.5) </span>// trying a higher threshold</p>
<p class="p11"><br></p>
<p class="p5">y.free;</p>
<p class="p5">x.free;</p>
<p class="p4">b.close</p>
<p class="p2"><br></p>
<p class="p2"><br></p>
<p class="p2"><br></p>
<p class="p2"><br></p>
<p class="p2"><br></p>
<p class="p2"><br></p>
<p class="p4">Based on the technique presented in this paper (but different - adapted for online estimation and with some other little differences):</p>
<p class="p2"><br></p>
<p class="p4">Zafar Rafii and Bryan Pardo. "A Simple Music/Voice Separation Method based on the Extraction of the Repeating Musical Structure," 36th International Conference on Acoustics, Speech and Signal Processing (ICASSP 2011), Prague, Czech Republic, May 22-27, 2011.</p>
<p class="p4">http://www.cs.northwestern.edu/~zra446/research.html</p>
<p class="p2"><br></p>
<p class="p2"><br></p>
</body>
</html>
